package com.ringtheweb.common.util.crypto;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

/**
 * Generate a secured random id. 
 * This generator is based on Secure Hash Algorithm Version 1.0 (SHA1)
 * developped by NIST for NSA.
 * Singleton pattern is used since 'SecureRandom' is resource expensive .
 * 
 * @author  ldewavri
 */

public class SecureId 
{   
    /** Singleton instance **/
	private static SecureId defaultInstance = new SecureId();
    
    /** Random generation algorithm **/
    private SecureRandom prng;
    
    /** 
     * Private Singleton Constructor
     * 
     * @throws NoSuchAlgorithmException 
     **/
    private SecureId() {
            try {
				this.prng = SecureRandom.getInstance("SHA1PRNG");
			} catch (NoSuchAlgorithmException e) {
				throw new IllegalStateException("NoSuchAlgorithm : SHA1PRNG");
			}   
    }
    
    /**
     * 
	 * @return The unique instance of this singleton.
	 * 
     * @throws NoSuchAlgorithmException 
	 * @see Double check locking pattern.
	 */
	public final static SecureId getInstance() {
		return SecureId.defaultInstance;
	}
    
    
    /**
	 * Generate random id.
	 * <i>Remarque : This method does not support the generation of id larger than 50 chars </i>
	 * 
	 * @param length - Length of the id to generate.
	 * @return String - The Secured id.
     * @throws NoSuchAlgorithmException 
	 */

    public String generate(int length) throws NoSuchAlgorithmException {
       
        String randomId = null;
       
        //Generation of a random number
        String randomNum = new Integer( this.prng.nextInt() ).toString();
    
        // Digest generation
        MessageDigest sha = MessageDigest.getInstance("SHA-1");
        byte[] result =  sha.digest( randomNum.getBytes() );
    
        //Extraction de la chaine
        randomId = hexEncode(result).substring(0,length);

        return randomId;
    }
    
    /**
     * Default generation of a 15 chars long id
     * 
     * @return A random id of 15 chars long
     * @throws NoSuchAlgorithmException
     */
    public long generate() throws NoSuchAlgorithmException {
        return Long.parseLong(generate(15), 16);
    }
    
   /**
    * Hexa to String encoding.
    * 
    * @param input - the byte input array.
    * @return the string transformed.
    */
    private String hexEncode( byte[] input){
    
        StringBuffer result = new StringBuffer();
        char[] digits = {'0', '1', '2', '3', '4','5','6','7','8','9','A','B','C','D','E','F'};
        
        for ( int idx = 0; idx < input.length; ++idx) {
          byte b = input[idx];
          result.append( digits[ (b&0xf0) >> 4 ] );
          result.append( digits[ b&0x0f] );
        }
        
        return result.toString();
  }
  
} 
